﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
//written by Pascal Schotman
namespace VisionApplication
{
    class FastPixelAccess
    {
        private byte[] rgbValues;
        private BitmapData bmpData;
        private IntPtr bmpPtr;

        private Bitmap bitmap;
        private int height;
        private int width;

        private bool locked = false;
        private bool alpha = false;

        //constructor to load bitmap in class
        public FastPixelAccess(Bitmap bitmap)
        {
            this.bitmap = bitmap;
            this.alpha = (this.Bitmap.PixelFormat == (this.Bitmap.PixelFormat | PixelFormat.Alpha));
            this.width = bitmap.Width;
            this.height = bitmap.Height;
        }

        public void Lock()
        {
            //is bmp locked?
            if (this.locked)
                throw new Exception("Bitmap already locked.");

            //not locked
            Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
            this.bmpData = this.Bitmap.LockBits(rect, ImageLockMode.ReadWrite, this.Bitmap.PixelFormat);
            this.bmpPtr = this.bmpData.Scan0;

            //alpha?
            if (this.IsAlphaBitmap)
            {
                int bytes = (this.Width * this.Height) * 4;
                this.rgbValues = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(this.bmpPtr, rgbValues, 0, this.rgbValues.Length);
            }
            else
            {
                int bytes = (this.Width * this.Height) * 3;
                this.rgbValues = new byte[bytes];
                System.Runtime.InteropServices.Marshal.Copy(this.bmpPtr, rgbValues, 0, this.rgbValues.Length);
            }
            this.locked = true;
        }

        public void Unlock(bool setPixels)
        {
            //is bmp locked?
            if (!this.locked)
                throw new Exception("Bitmap not locked.");

            // Copy the RGB values back to the bitmap;
            if (setPixels)
                System.Runtime.InteropServices.Marshal.Copy(this.rgbValues, 0, this.bmpPtr, this.rgbValues.Length);

            // Unlock the bits.;
            this.Bitmap.UnlockBits(bmpData);
            this.locked = false;
        }

        public void SetPixel(int x, int y, Color color)
        {
            //is bmp locked?
            if (!this.locked)
                throw new Exception("Bitmap not locked.");

            //alpha?
            if (this.IsAlphaBitmap)
            {
                int index = ((y * this.Width + x) * 4);
                this.rgbValues[index] = color.B;
                this.rgbValues[index + 1] = color.G;
                this.rgbValues[index + 2] = color.R;
                this.rgbValues[index + 3] = color.A;
            }
            else
            {
                int index = ((y * this.Width + x) * 3);
                this.rgbValues[index] = color.B;
                this.rgbValues[index + 1] = color.G;
                this.rgbValues[index + 2] = color.R;
            }
        }

        public Color GetPixel(int x, int y)
        {
            //is bmp locked?
            if (!this.locked)
                throw new Exception("Bitmap not locked.");

            //alpha?
            if (this.IsAlphaBitmap)
            {
                int index = ((y * this.Width + x) * 4);
                int b = this.rgbValues[index];
                int g = this.rgbValues[index + 1];
                int r = this.rgbValues[index + 2];
                int a = this.rgbValues[index + 3];
                return Color.FromArgb(a, r, g, b);
            }
            else
            {
                int index = ((y * this.Width + x) * 3);
                int b = this.rgbValues[index];
                int g = this.rgbValues[index + 1];
                int r = this.rgbValues[index + 2];
                return Color.FromArgb(r, g, b);
            }
        }
        public int Width
        {
            get
            {
                return this.width;
            }
        }

        public int Height
        {
            get
            {
                return this.height;
            }
        }

        public bool IsAlphaBitmap
        {
            get
            {
                return this.alpha;
            }
        }

        public Bitmap Bitmap
        {
            get
            {
                return this.bitmap;
            }
        }
    }

}
